﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;
using Xenta.Utils;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the seller entity.
    /// </summary>
    /// <remarks><pre>
    /// The entity regarding the disclosure level.
    /// 
    /// + Entire
    ///  | - Addresses(of the Extended level)
    ///  + Extended
    ///   + Base
    ///    | - CommentCount
    ///    | - RatingCount
    ///    | - RatingAverage
    ///    | - DisplayName
    ///    | - Flags
    ///    | - UpdatedOn
    ///    | - CreatedOn
    ///    + Keys
    ///     | - Account(of the same level)
    ///     + Primary
    ///      | - EntityID
    /// 
    /// Note: upper level includes lower level.
    /// </pre></remarks>
    public class SellerEntity : AccountProfileEntity
    {
        #region Fields

        private ICollection<SellerRatingEntity> _ratings;
        private ICollection<SellerCommentEntity> _comments;
        private ICollection<SalesItemEntity> _items;
        private ICollection<OrderEntity> _orders;
        private ICollection<SellerAddressEntity> _addresses;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SellerEntity()
        {
            _ratings = new List<SellerRatingEntity>();
            _comments = new List<SellerCommentEntity>();
            _items = new List<SalesItemEntity>();
            _orders = new List<OrderEntity>();
            _addresses = new List<SellerAddressEntity>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the numer of comments.
        /// </summary>
        public virtual int CommentCount
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the numer of ratings.
        /// </summary>
        public virtual int RatingCount
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the average rating.
        /// </summary>
        public virtual byte RatingAverage
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the display name.
        /// </summary>
        public virtual string DisplayName
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public virtual SellerFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Collections

        /// <summary>
        /// Gets the ratings.
        /// </summary>
        public virtual ICollection<SellerRatingEntity> Ratings
        {
            get
            {
                return _ratings;
            }
            set
            {
                _ratings = value;
            }
        }

        /// <summary>
        /// Gets the comments.
        /// </summary>
        public virtual ICollection<SellerCommentEntity> Comments
        {
            get
            {
                return _comments;
            }
            set
            {
                _comments = value;
            }
        }

        /// <summary>
        /// Gets or sets the item collection.
        /// </summary>
        public virtual ICollection<SalesItemEntity> Items
        {
            get
            {
                return _items;
            }
            set
            {
                _items = value;
            }
        }

        /// <summary>
        /// Gets or sets the order collection.
        /// </summary>
        public virtual ICollection<OrderEntity> Orders
        {
            get
            {
                return _orders;
            }
            set
            {
                _orders = value;
            }
        }

        /// <summary>
        /// Gets or sets the address collection.
        /// </summary>
        public virtual ICollection<SellerAddressEntity> Addresses
        {
            get
            {
                return _addresses;
            }
            set
            {
                _addresses = value;
            }
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Base)
            {
                obj["CommentCount"] = CommentCount;
                obj["RatingCount"] = RatingCount;
                obj["RatingAverage"] = RatingAverage;
                obj["DisplayName"] = DisplayName;
                obj["Flags"] = Flags.ToString();
            }
            if(level >= DisclosureLevel.Entire)
                obj["Addresses"] = Addresses.Map(x => x.Disclose(DisclosureLevel.Extended, options));
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapping.
    /// </summary>
    public class SellerMapping : EntityMapping<SellerEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SellerMapping()
        {
            Table("fwk_Sellers");
            Id(x => x.EntityID, m =>
            {
                m.Column("SellerID");
                m.Generator(Generators.Identity);
            });
            ManyToOne(x => x.Account, m =>
            {
                m.Column("AccountID");
                m.ForeignKey("FK_fwk_Sellers_fwk_Accounts");
                m.Index("IX_fwk_Sellers");
                m.NotNullable(true);
            });
            Property(x => x.CommentCount, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.RatingCount, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.RatingAverage, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.DisplayName, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.Flags, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Bag(x => x.Items, m =>
            {
                m.Table("fwk_SalesItems");
                m.Key(k =>
                {
                    k.Column("SellerID");
                    k.ForeignKey("FK_fwk_SalesItems_fwk_Sellers");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Bag(x => x.Comments, m =>
            {
                m.Table("fwk_Comments");
                m.Key(k =>
                {
                    k.Column("HolderID");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Bag(x => x.Ratings, m =>
            {
                m.Table("fwk_Ratings");
                m.Key(k =>
                {
                    k.Column("HolderID");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Bag(x => x.Orders, m =>
            {
                m.Table("fwk_Orders");
                m.Key(k =>
                {
                    k.Column("SellerID");
                    k.ForeignKey("FK_fwk_Orders_fwk_Sellers");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Bag(x => x.Addresses, m =>
            {
                m.Table("fwk_Addresses");
                m.Key(k =>
                {
                    k.Column("HolderID");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Cache(m =>
            {
                m.Usage(CacheUsage.ReadWrite);
            });
        }
    }
}
